
#Requires AutoHotkey v2.0
#Include TextProcessor.ahk

#Include FileTool.ahk
#Include SimLog.ahk

; 处理CSV文件(v1.03)
; 已知BUG
; # 单元格数据中不能包含"字符，否则会出现未知错误

class CSV_Pcr extends TextProcessor {

    ; 日志对象
    logger := Simlog()

    ; csv文件原文
    text := ""

    ; csv文件中共有多少个单元格
    cellCount := -1

    ; csv数据(二维数组)
    content := []

    ; 异常提示
    errTip := "#无数据#"

    ; ????
    special := [",", "`n", "`r"]

    ; 无效字符(逗号，回车，换行，引号)
    invalid := ',`r`n`"'

    ; 分割符
    separator := ","

    ; 行分割符
    lineSeparator := "`n"

    __new(text := "") {

        ; 日志相关设置
        this.logger.enable := true ; 日志是否启用
        this.logger.level := 2 ; trace级别的日志不再输出

        ; 加载csv
        this.Load(text)
    }

    ; 加载
    load(text := this.text) {

        ; 写日志
        this.logger.debug(Format("{1}(text):尝试加载数据...", A_ThisFunc))

        ; row不是一个字符串 & 为空
        if (Type(text) != "String" || text = "") {
            this.logger.debug(Format("{1}():加载失败", A_ThisFunc))
            return
        }

        ; 默认参数
        this.text := text
        this.cellCount := 0

        logText := A_ThisFunc . "():"


        ; 声明局部变量
        local rows := [], cells := []

        ; 声明局部变量
        local s := 1, e := 1, len := StrLen(this.text)

        ; 放行(此参数为true,知道遇到了另外一个引号,不再判断其他字符)
        local proceed := false

        ; 换行(此参数为true,表示这条数据是一行的最后一条数据)
        local enter := false

        loop parse Trim(this.text) {

            if (A_LoopField == '`"') { ; 引号

                proceed := !proceed ; 取反

            }

            if (proceed) {
                continue
            }

            if (A_LoopField == this.separator) { ; 分割符
                e := A_Index
            }

            if (A_LoopField == this.lineSeparator) { ; 换行分割符
                e := A_Index

                ; 标记这条数据是本行的最后一条数据
                enter := true
            }

            if (e != s) { ; 如果开始坐标与结束坐标不同，说明到了一条数据结束的位置

                this.cellCount++ ;计数

                ; 切割字符串
                t := e - s
                cell := SubStr(this.text, s, (e - s))

                cell := Trim(cell, this.invalid) ; 去掉多余(无效)字符

                cells.Push(cell)

                ; 详细日志(不输出)
                this.logger.trace("读取: text[i:" . A_Index . "] 截取[s:" . s . ",e:" . e . "] (" . cell . ")")

                s := e ; 跳过(s等于e,继续循环)

                ; 按行归档
                if (enter) {
                    enter := false
                    rows.Push(cells) ; 存入数组
                    cells := [] ; 置零
                }
            }

        }

        ; 如果最后一行有数据
        if (cells.Length != 0) {
            rows.Push(cells) ; 存入最后一行数据
        }

        this.content := rows

        ; 写日志
        this.logger.debug(Format("{1}():加载成功(共{2}行)", A_ThisFunc, this.content.Length))

        return this.content
    }

    ; 写
    toCSV(content := this.content) {

        ; 写日志
        this.logger.debug(Format("{1}(content):尝试输出到csv文件...", A_ThisFunc))

        this.content := content

        ; 声明局部变量
        local rows := "", row

        loop this.content.Length {

            ; 临时变量
            row := this.content[A_Index]
            rowIndex := A_Index

            loop row.Length {

                ; 拼接单元格数据
                rows .= this._formatCell(row[A_Index])

                ; 记录日志
                this.logger.trace(Format("写入: 单元格[{1}][{2}]({3}) --> text", rowIndex, A_Index, row[A_Index]))

                ; 拼接分割符(如果不是一行的最后一个元素)
                if (A_Index != row.Length) {
                    rows .= this.separator
                }
            }
            ; 拼接行分割符
            rows .= this.lineSeparator
        }

        this.text := rows

        ; 写日志
        this.logger.debug(Format("{1}(content):输出成功...", A_ThisFunc))

        return this.text
    }

    ; 添加一行数据
    addRow(row, position := "after") {

        ; 记录日志
        logText := "["
        loop row.Length {
            logText .= row[A_Index]
            if (A_Index != row.Length) {
                logText .= ","
            }
        }
        logText .= "]"
        logText := Format("{1}(row={2}, positon={3})", A_ThisFunc, logText, position)

        this.logger.debug(logText)


        ; row没有被正确赋值
        if (!row) {
            return
        }

        ; row不是一个对象
        if (!IsObject(row)) {
            return
        }

        ; row不是一个数组
        if (Type(row) != "Array") {
            return
        }

        switch position, 0 {
            case "before":
                this.content.InsertAt(1, row)
            case "after":
                this.content.Push(row)
            default:
                if (Type(position) = "Integer") { ; 是整数
                    if (position >= 1 && position <= this.content.Length) { ; 数据有效(作为数组下标)
                        this.content.InsertAt(position, row)
                        this.logger.debug(Format("{1}():添加成功", A_ThisFunc))
                        return
                    }
                }
                this.logger.debug(Format("{1}():添加失败", A_ThisFunc))
        }

        this.logger.debug(Format("{1}():添加成功", A_ThisFunc))

    }
    ; 获取某个单元格的数据(row 第几行 col 第几列)
    getCell(row, col) {

        ; 写日志
        this.logger.debug(Format("{1}():查询单元格[{2},{3}]...", A_ThisFunc, row, col))

        if (!this.content) { ; 不存在
            return this.errTip
        }

        if (this.content.length == 0) {
            return this.errTip ; 无数据
        }

        ; 尝试捕获异常(数组下标越界)
        try {
            testText := this.content[row][col]
        } catch Error as e {
            ; 写日志
            this.logger.debug(Format("{1}():查询失败[{2},{3}] : ({4})...", A_ThisFunc, row, col, this.errTip))
            return this.errTip
        }
        
        ; 写日志
        this.logger.debug(Format("{1}():查询成功[{2},{3}] : ({4})...", A_ThisFunc, row, col, this.content[row][col]))

        return this.content[row][col]
    }

    ; 格式化单元格
    _formatCell(cell) {

        loop parse cell {
            switch A_LoopField {
                case ",": cell := this._addQuote(cell)
                    break
                case "`n": cell := this._addQuote(cell)
                    break
            }
        }

        return cell
    }

    ; 加引号
    _addQuote(cell) {
        return Format('`"{1}`"', cell)
    }

}


